import axios from 'axios'
import {
  rsa,
  AESEncode,
  AESDecode,
  sha256,
  decryptPublic
} from '@/plugins/utils/encode'

import {
  $tokenName,
  $getToken,
  $setToken,
  $formatSearchParam,
  $version
} from '@/plugins/baseInfo'
import $event from '@/plugins/utils/event'
import {
  notification,
  message
} from 'antd';


import {v4 as uuidv4} from 'uuid'

axios.defaults.headers.post['Content-Type'] = 'application/json'

const isDev = process.env.NODE_ENV === 'development'

// 创建一个 axios 实例
const $axios = axios.create({
  timeout: 60000
  // headers: {
  //   'userId': store.getters.userId ? store.getters.userId : ''
  // }
})

const CancelToken = axios.CancelToken
const pending = []
// 请求开始和完成后清除缓冲池
const cancelPending = ({
  url,
  method
}) => {
  pending.forEach(({
    u,
    c
  }, i) => {
    // 当缓存池中的请求地址和传入的一样时取消缓存池中的请求
    if (u === `${url}&${method}`) {
      c('取消重复请求')
      // 取消后删除缓存池中的记录
      pending.splice(i, 1)
    }
  })
}
// 新增缓存
const addPending = (config) => {
  const {
    data = {}, url, method
  } = config
  if (data._cancelRepeat) {
    cancelPending(config)
    config.cancelToken = new CancelToken(function executor(cancel) {
      // 缓存请求
      pending.push({
        u: `${url}&${method}`,
        c: cancel,
        m: method
      })
    })
    delete data._cancelRepeat
  }
}

const url_encrypt = ['/account/encryptLogin', '/account/encryptPassword']

const { encrypt_version } = window.global_config  // 全局配置文件

// 请求拦截器
$axios.interceptors.request.use(
  (config) => {
    if (encrypt_version === '1.0' && url_encrypt.some(r => config.url.indexOf(r) > -1)) {
      config.data = paramsEncode(config)
    }
    config.headers.common['Authorization'] = $getToken()
    // // config.headers.common['Encrypt-version'] = encrypt_version   // 暂时隐藏，全局接口加密需放开
    // config.headers = Object.assign(window.g.header, config.headers)
    // addPending(config)
    return config
  },
  (error) => {
    // 发送失败
    Promise.reject(error)
  }
)

// 响应拦截器
$axios.interceptors.response.use(
  (response) => {
    // cancelPending(response.config)

    const data = response.data
    const headers = response.headers
    // 统一对code进行强转处理
    data.status = Number(data.code || data.resCode || data.status)
    if (data.status !== 200) {
      message.warning({
        content: data.message,
        duration: 3
      })
      return Promise.reject(data)
    }
    return data
  },
  (error) => {
    if (error && error.response) {
      if ([401, 504].includes(Number(error.response.status))) {
        $event.trigger('login-out')
        return
      }
      const errorMessage = error.response.data && error.response.data.message
      switch (error.response.status) {
        case 100:
          error.message = '参数不能为空';
          break
        case 101:
          error.message = '未查询到数据';
          break
        case 102:
          error.message = '未整合所有县市下可研成果信息';
          break
        case 400:
          error.message = '请求格式错误、参数错误';
          break
        case 401:
          error.message = '未授权,请重新登录';
          break
        case 404:
          error.message = '请求的资源不存在、数据不存在';
          break
        case 409:
          error.message = '资源存在冲突、数据已存在';
          break
        case 410:
          error.message = '重复提交';
          break
        case 424:
          error.message = '违背数据完整性、当插入、删除和修改数据的时候，违背的数据完整性约束抛出的异常。例如：主键重复异常、存在外键关联数据依赖等';
          break
        case 425:
          error.message = '关联关系重复';
          break
        case 426:
          error.message = 'http解析异常';
          break
        case 427:
          error.message = '关联文件删除异常';
          break
        case 428:
          error.message = '关联文件不存在';
          break
        case 429:
          error.message = '未定义流程';
          break
        case 430:
          error.message = '文件为空，请重新上传';
          break
        case 431:
          error.message = '存在未审核包，请审核通过后进行打包';
          break
        case 432:
          error.message = '存在项目名称一样，请修改项目名称';
          break
        case 500:
          error.message = errorMessage || '服务器内部错误';
          break
        default:
          break
      }
    }
    if (error.constructor.name !== 'Cancel') {
      notification.warning({
        message: '错误',
        description: error.message,
        duration: 2
      })
    }

    return Promise.reject(error)
  }
)




// 参数加密
export const paramsEncode = (config) => {
  const params = {}
  // 登录用户名
  const token = $getToken()
  token && (params.authorization = token)
  // 数据加密AES密钥，客户端生成的随机字符串
  const key_str = uuidv4().toString().replace(/-/g, '')
  const dataKey = rsa(key_str)
  // 请求参数aes加密
  const configData = AESEncode(JSON.stringify(config.data), key_str)

  params.data = configData

  params.dataKey = dataKey
  // 服务编码,请求地址去掉'/'
  params.serviceCode = config.url.replace(/\//g, '')
  // 时间戳
  params.time = new Date().getTime()
  // 随机数
  params.uuid = uuidv4().toString().replace(/-/g, '')
  // 请求数据签名,对params的json字符串进行SHA256算法计算摘要，然后使用公钥进行加密
  const sign = rsa(sha256(JSON.stringify(params)))
  return {
    params,
    sign
  }
}

// 结果解密
export const paramsDecrypt = ({
  params,
  sign
}) => {
  // 验证与本地计算出来的sign比较
  const loaclSign = sha256(JSON.stringify(params))
  sign = decryptPublic(sign)
  if (sign !== loaclSign) {
    // Message.error({
    //   message: '数据在传输过程中被修改，请在安全的网络环境下操作',
    //   duration: 2000
    // })
    return
  }
  // 数据加密aes秘钥, rsa进行解密
  const dataKey = decryptPublic(params.dataKey)
  // 响应给客户端的数据，根据aes秘钥进行ase解密
  const data = AESDecode(params.data, dataKey)
  return JSON.parse(data)
}

export default $axios